﻿using System;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;

namespace FuckCore.DAO
{
    /// <summary>
    /// This is base class of all Data Access class.
    /// It contains general methods of Data Access class as following:
    /// Add,Update,Delete,SaveChanges,GetByQuery
    /// In BaseDAO,allways exitsed an ObjectContext to work with Data Enterprise to access database.
    /// </summary>
    /// <typepara name="TObjectContext">ObjectContext to access to database</typepara>
    /// <typepara name="TEntity">Entity object needs to be processed</typepara>
    /// <remarks>
    /// created by: ThangLD
    /// created date: 30 may 2009
    /// modified by: N/A
    /// modified date: N/A
    /// </remarks>
    public class BaseDAO<TObjectContext, TEntity> : IDAO<TEntity>
        where TObjectContext : ObjectContext, new()
        where TEntity : EntityObject
    {
        /// <summary>
        /// Returns an ObjectContext object. 
        /// </summary>
        public TObjectContext ObjectContext
        {
            get
            {
                TObjectContext _ObjectContext = DAOScope.GetCurrentObjectContext<TObjectContext>();
                Type type = _ObjectContext.GetType();
                _ObjectContext.MetadataWorkspace.LoadFromAssembly(type.Assembly);
                return _ObjectContext;
            }
        }

        #region IDAO<TEntity> Members

        /// <summary>
        /// Adds a new entity object to the context.
        /// </summary>
        /// <para name="newEntity">A new object.</para>
        public void Add(TEntity newEntity)
        {
            ObjectContext.AddObject(newEntity.GetType().Name, newEntity);
            ObjectContext.SaveChanges();
        }

        /// <summary>
        /// Deletes an entity object.
        /// </summary>
        /// <para name="obsoleteEntity">An obsolete object.</para>
        public void Delete(TEntity obsoleteEntity)
        {
            object currentEntityInDb;
            ObjectContext.TryGetObjectByKey(obsoleteEntity.EntityKey, out currentEntityInDb);
            ObjectContext.DeleteObject(currentEntityInDb);
            ObjectContext.SaveChanges();
        }

        /// <summary>
        /// Update Entity Methode
        /// </summary>
        /// <para name="updatedEntity">entity to update</para>
        public void Update(TEntity updatedEntity)
        {
            object currentEntityInDb;
            try
            {
                ObjectContext.TryGetObjectByKey(updatedEntity.EntityKey, out currentEntityInDb);
                ObjectContext.ApplyPropertyChanges(((TEntity)currentEntityInDb).EntityKey.EntitySetName, updatedEntity);
                int save = ObjectContext.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new ObjectNotFoundException();
            }
            //if (ObjectContext.TryGetObjectByKey(updatedEntity.EntityKey, out currentEntityInDb))
            //{
            //    ObjectContext.SaveChanges();
            //}
            //else
            //{
            //    throw new ObjectNotFoundException();
            //}
        }

        /// <summary>
        /// Get List of Entity by Queryable
        /// </summary>
        /// <typepara name="TEntity"></typepara>
        /// <para name="query"></para>
        /// <returns></returns>
        public ReadOnlyCollection<TEntity> GetByQuery(IQueryable<TEntity> query)
        {
            return new ReadOnlyCollection<TEntity>(query.ToList());
        }


        ///<summary>
        ///</summary>
        ///<param name="query"></param>
        ///<returns></returns>
        public IQueryable<TEntity> Search(string query)
        {
            ObjectQuery<TEntity> objectQuery = new ObjectQuery<TEntity>(query, ObjectContext, MergeOption.NoTracking);
            return objectQuery;
        }
        #endregion

        public void SaveChanges()
        {
            ObjectContext.SaveChanges();
        }
    }
}